package com.nx.platform.es.biz.esspider.handler;

import com.google.common.primitives.Ints;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.nx.platform.es.common.utils.MoreSplitters;
import com.nx.platform.es.common.utils.Utils;
import com.nx.platform.es.biz.esspider.entity.Item;
import com.nx.platform.es.common.utils.MoreFunctions;
import com.nx.platform.es.common.utils.MoreMaps;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author
 * @since 2017年3月27日
 */
@HandlerDefine(HandlerType.SIMPLE)
public class SimpleParamsMapConvertHandler extends AbstractSimpleHandler {

    private static final Type PARAMS_TYPE = new TypeToken<Map<String, String>>() {}.getType();
    private static final Logger LOGGER = LogManager.getLogger(SimpleParamsMapConvertHandler.class);
    private static final Gson GSON = new GsonBuilder().create();

    private String field;

    @Override
    public void init(Map<?, ?> settings) throws Exception {
        field = MoreMaps.getString(settings, "field", "params");
    }

    @Override
    public void handle(Map<Long, Item> items) throws Exception {
        items.values().forEach((Item item) ->
                item.getDoc().put(field, convertParams(item.getDoc().remove(field)))
        );
    }

    private List<Long> convertParams(Object object) {
        if (object != null && object instanceof String) {
            try {
                Map<String, String> params = GSON.fromJson(String.valueOf(object), PARAMS_TYPE);
                if (params != null) {
                    Map<Integer, List<Integer>> map = new HashMap<>(params.size());
                    for (Map.Entry<String, String> e : params.entrySet()) {
                        Integer key = Ints.tryParse(e.getKey());
                        List<Integer> value = MoreFunctions.toIntegerList(e.getValue(), MoreSplitters.VERTICAL_OR_COMMA);
                        if (key != null && value != null && !value.isEmpty()) {
                            map.put(key, value);
                        }
                    }
                    return mergeParams(map);
                }
            } catch (Throwable e) {
                LOGGER.warn("convert params error: {}", object, e);
            }
        }
        return Collections.emptyList();
    }

    private List<Long> mergeParams(Map<Integer, List<Integer>> params) {
        return params.entrySet().stream().flatMap(e -> {
            Integer key = e.getKey();
            if (key == null) {
                return Stream.empty();
            }
            return e.getValue().stream().map(v -> Utils.merge(key, v));
        }).collect(Collectors.toList());
    }

}
